package com.neasho.neashoadminv1.infrastructure.permission

import cn.hutool.http.useragent.UserAgentUtil
import com.neasho.neashoadminv1.web.service.sys.SysUserTokenService
import com.neasho.neashoadminv1.infrastructure.utils.UserContext
import com.neasho.neashoadminv1.infrastructure.utils.ulid
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import org.springframework.stereotype.Component
import org.springframework.util.StringUtils
import org.springframework.web.servlet.HandlerInterceptor
import java.util.*
import java.util.concurrent.TimeUnit


@Target(AnnotationTarget.TYPE, AnnotationTarget.FUNCTION) // 修改: 支持标注在类和方法上
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class ApiAuth(
    val value: Array<String> = [],
) {
}

@Component
class UserContextInitInterceptor(
    var sysUserTokenService: SysUserTokenService
) : HandlerInterceptor {
    val AUTHORIZATION_HEADER = "Authorization"

    override fun preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any): Boolean {
        val token = request.getHeader(AUTHORIZATION_HEADER)
        if (StringUtils.hasLength(token)) {
            val user = sysUserTokenService.getUserByToken(token)
            UserContext.setUser(user)
        }
        // 解析浏览器客户端信息
        val userAgent = UserAgentUtil.parse(request.getHeader("User-Agent"))
        UserContext.setUserAgent(userAgent!!)
        return true
    }

    override fun afterCompletion(
        request: HttpServletRequest,
        response: HttpServletResponse,
        handler: Any,
        ex: Exception?
    ) {
        UserContext.clear()
        UserContext.clearUserAgent()
    }

}


object OneOffTokenManager {
    private val TOKEN_MAP: MutableMap<String, OneOffToken> = HashMap<String, OneOffToken>()

    /**
     * 申请新token
     *
     * @param token
     * @return
     */
    fun applyNewOne(token: String): String {
        val applyTime = Date().time
        val oneOffToken = OneOffToken(token, ulid(), applyTime, applyTime + TimeUnit.MINUTES.toMillis(3))
        TOKEN_MAP.put(oneOffToken.token, oneOffToken)
        return oneOffToken.token
    }

    fun validToken(token: String): Boolean {
        val oneOffToken = TOKEN_MAP.get(token)
        if (oneOffToken != null && oneOffToken.expireTime!! > Date().getTime()) {
            return true
        }
        if (TOKEN_MAP.containsKey(token)) {
            TOKEN_MAP.remove(token)
        }
        return false
    }

    fun getOriginalToken(tmpToken: String): String {
        val oneOffToken: OneOffToken = TOKEN_MAP.remove(tmpToken)!!
        return oneOffToken.originToken
    }

}



class OneOffToken(
    val originToken: String,
    val token: String,
    val applyTime: Long,
    val expireTime: Long,
) {}